package util;

import java.awt.Color;
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import model.GameModel;
import model.entities.Direction;
import model.entities.LaserSource;
import model.entities.Mirror;
import model.entities.MirrorOrientation;
import model.entities.Wall;
import model.entities.targets.TransparentTarget;

/**
 * Handles pretty much everything dealing with loading levels.
 * 
 * Some methods are commented out because I would like to create
 * two versions of these, one for aplett and one for desktop app and
 * I didnt want to lose them.
 * 
 * This was meant to be a static utility class but we had to work around
 * for the applet I/O issue.
 * 
 *
 */
public class LevelUtils {

//	private static final String LEVEL_DIRECTORY = "/levels/";
	private static final String LEVEL_EXTENSION = ".level";
	
	private static final String RED_SRC_LOCATION_NAME = "redSourceLocations";
	private static final String GREEN_SRC_LOCATION_NAME = "greenSourceLocations";
	private static final String BLUE_SRC_LOCATION_NAME = "blueSourceLocations";
	private static final String MIRROR_LOCATION_NAME = "mirrorLocations";
	
	private static final String WALL_LOCATION_NAME = "wallLocations";
	
	private static final String RED_TARGET_LOCATION_NAME = "redTargetLocations";
	private static final String GREEN_TARGET_LOCATION_NAME = "greenTargetLocations";
	private static final String BLUE_TARGET_LOCATION_NAME = "blueTargetLocations";
	private static final String CYAN_TARGET_LOCATION_NAME = "cyanTargetLocations";
	private static final String MAGENTA_TARGET_LOCATION_NAME = "magentaTargetLocations";
	private static final String YELLOW_TARGET_LOCATION_NAME = "yellowTargetLocations";
	private static final String WHITE_TARGET_LOCATION_NAME = "whiteTargetLocations";
	
	private static final String RED_SOURCE_BANK_NAME = "itemsInRedSourceBank";
	private static final String GREEN_SOURCE_BANK_NAME = "itemsInGreenSourceBank";
	private static final String BLUE_SOURCE_BANK_NAME = "itemsInBlueSourceBank";
	private static final String MIRROR_BANK_NAME = "itemsInMirrorBank";
	
//	public void parseLevel(String levelName, GameModel model) throws URISyntaxException, IOException {
//		if (levelName == null)
//			return;
//		File[] levelFileList = getLevelList();
//		String fullName = levelName.concat(LEVEL_EXTENSION);
//		
//		for (File file : levelFileList) {
//			if (file.getName().equals(fullName)) {
//				parseLevel(file, model);
//				break;
//			}
//		}
//		
//	}
	
//	public void parseLevel(File level, GameModel model) throws IOException {
//		
//		model.createNewGameBoard();
//		model.createNewBin();
//		
//		FileReader levelFileReader = new FileReader(level);
//		BufferedReader levelReader = new BufferedReader(levelFileReader);
//		
//		String line = levelReader.readLine();
//		
//		while(line != null) {
//			
//			if (line.trim().equals("") || line.startsWith("#")) { // empty line or comment
//				line = levelReader.readLine();
//				continue;
//			}
//		
//			if (!line.contains("="))
//				throw new IOException("Malformed Level File: Expecting '='");
//			
//			String[] splitLine = line.split("=");
//			
//			if (splitLine.length != 2)
//				throw new IOException("Malformed Level File");
//			
//			String entityName = splitLine[0];
//			String entityData = splitLine[1];
//			
//			insertEntities(entityName.trim(), entityData.trim(), model);
//			
//			line = levelReader.readLine();
//		} 
//	}
	
	public void parseLevel(String level, GameModel model) throws IOException {
		
		model.createNewGameBoard();
		model.createNewBin();

		//URL url = ClassLoader.getSystemResource(level + LEVEL_EXTENSION);
		URL url = this.getClass().getResource("/" + level + LEVEL_EXTENSION);
		InputStream stream = url.openStream();
		Reader reader = new InputStreamReader(stream);
		BufferedReader levelReader = new BufferedReader(reader);
		
		String line = levelReader.readLine();
		
		while(line != null) {
			
			if (line.trim().equals("") || line.startsWith("#")) { // empty line or comment
				line = levelReader.readLine();
				continue;
			}
		
			if (!line.contains("="))
				throw new IOException("Malformed Level File: Expecting '='");
			
			String[] splitLine = line.split("=");
			
			if (splitLine.length != 2)
				throw new IOException("Malformed Level File");
			
			String entityName = splitLine[0];
			String entityData = splitLine[1];
			
			insertEntities(entityName.trim(), entityData.trim(), model);
			
			line = levelReader.readLine();
		} 
	}
	
	private static void insertEntities(String entityName, String entityData, GameModel model) throws IOException {
		
		if (RED_SRC_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				LaserSource source = new LaserSource(Color.RED, Direction.TOP);
				model.getGameBoard().addEntity(source, point);
			}
		}
		else if (GREEN_SRC_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				LaserSource source = new LaserSource(Color.GREEN, Direction.TOP);
				model.getGameBoard().addEntity(source, point);
			}
		}
		else if (BLUE_SRC_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				LaserSource source = new LaserSource(Color.BLUE, Direction.TOP);
				model.getGameBoard().addEntity(source, point);
			}
		}
		else if (MIRROR_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				Mirror mirror = new Mirror(MirrorOrientation.VERTICAL);
				model.getGameBoard().addEntity(mirror, point);
			}
		}
		else if (WALL_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				Wall wall = new Wall();
				model.getGameBoard().addEntity(wall, point);
			}
		}
		else if (RED_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.RED);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (GREEN_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.GREEN);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (BLUE_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.BLUE);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (CYAN_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.CYAN);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (MAGENTA_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.MAGENTA);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (YELLOW_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.YELLOW);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (WHITE_TARGET_LOCATION_NAME.equals(entityName)) {
			List<Point> points = getPointList(entityData);
			for (Point point : points) {
				TransparentTarget target = new TransparentTarget(Color.WHITE);
				model.getGameBoard().addEntity(target, point);
			}
		}
		else if (RED_SOURCE_BANK_NAME.equals(entityName)) {
			int numSources = Integer.parseInt(entityData);
			for (int i = 0; i < numSources; i++) {
				model.getBin().putRedSource();
			}
		}
		else if (GREEN_SOURCE_BANK_NAME.equals(entityName)) {
			int numSources = Integer.parseInt(entityData);
			for (int i = 0; i < numSources; i++) {
				model.getBin().putGreenSource();
			}
		}
		else if (BLUE_SOURCE_BANK_NAME.equals(entityName)) {
			int numSources = Integer.parseInt(entityData);
			for (int i = 0; i < numSources; i++) {
				model.getBin().putBlueSource();
			}
		}
		else if (MIRROR_BANK_NAME.equals(entityName)) {
			int numSources = Integer.parseInt(entityData);
			for (int i = 0; i < numSources; i++) {
				model.getBin().putMirror();
			}
		}
	}
	
	private static List<Point> getPointList(String data) throws IOException {
		
		List<Point> pointList = new ArrayList<Point>();
		String[] points;
		data.replaceAll("\\s",""); // remove spaces
		
		if (!data.contains(";")) {
			points = new String[1];
			points[0] = data.trim();
		}
		else {
			points = data.split(";");
		}

		for (String nextPoint : points) {
			if (!nextPoint.contains(","))
				throw new IOException("Malformed Level File: Expecting ','");
			
			String[] split = nextPoint.split(",");
			
			if (!nextPoint.contains(",") || split.length != 2)
				throw new IOException("Malformed Level File");
			
			String xString = split[0].trim();
			String yString = split[1].trim();
			
			int x = Integer.parseInt(xString);
			int y = Integer.parseInt(yString);
			
			Point newPoint = new Point(x,y);
			pointList.add(newPoint);
		}
		
		return pointList;
	}
	
//	public File[] getLevelList() throws URISyntaxException {
//		
//		URL url = ClassLoader.getSystemResource("levelList");
//		
//		File levelFolder = new File(url.toURI());
//		FilenameFilter filter = new FilenameFilter() {
//			
//			@Override
//			public boolean accept(File dir, String name) {
//				if (name.endsWith(LEVEL_EXTENSION))
//					return true;
//				else
//					return false;
//			}
//		};
//		
//		File[] levelList = levelFolder.listFiles(filter);
//		return levelList;
//	}
	
	public String[] getLevelNames() throws IOException {
		
		ArrayList<String> tempList = new ArrayList<String>();
		
		//URL url = ClassLoader.getSystemResource("levelList");
		URL url = this.getClass().getResource("/levelList");
		InputStream stream = url.openStream();
		Reader reader = new InputStreamReader(stream);
		BufferedReader bufReader = new BufferedReader(reader);
		
		String line = bufReader.readLine();
		
		while (line != null) {
			tempList.add(line);
			line = bufReader.readLine();
		}
		
		String[] outList = new String[tempList.size()];
		
		for (int i = 0 ; i < tempList.size(); i ++) {
			outList[i] = tempList.get(i);
		}
		
		//Arrays.sort(outList); // maybe not sort now since the order can be determined
						      // by the user in the levelList file
		return outList;
		
	}
	
//	public static String[] getLevelNames(File[] levelList) {
//		String[] levelNames = new String[levelList.length];
//		
//		for (int i = 0; i < levelList.length; i++) {
//			String levelName = levelList[i].getName();
//			String[] newName = levelName.split("\\.");
//			levelNames[i] = newName[0];
//		}
//		
//		Arrays.sort(levelNames);
//		
//		return levelNames;
//	}
}
